﻿/*
 * Created by SharpDevelop.
 * User: iroberts
 * Date: 2/24/2013
 * Time: 10:54 AM
 */
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.IO; // Access to FileSystemWatch
using System.ComponentModel; // Access to BackgroundWorker
using System.Collections; // Access to Hashtable

namespace SrcWatch {
	public partial class MainForm : Form 	{
		// Simple toggle for whether the app is currently actively monitoring
		private Boolean bWatching = false;

		// Create system object
		private FileSystemWatcher fswWatcher = new FileSystemWatcher();
		
		// This hashtable is used to store the last write times of all files during this session
		// We do this because the FSW will quite frequently report multiple duplicate events for the same file because
		// of the way applications write to disk in Windows
		private Hashtable fileWriteTime = new Hashtable();
		
		// An array of file extensions we will check
		private List<string> lstExtensions = new List<string>();
		
		// A couple of strings to hold the src and target vars
		private String strSrcDir = "";
		private String strTargetDir = "";
		
		public MainForm() 		{
			InitializeComponent();
		}
		
		private void MainFormLoad (object sender, EventArgs e)
		{
			// This is very, very NAUGHTY!
			// I'm doing this because the filesystemwatchers events operate on a different thread from the UI
			// So, in order to update the UI I need to implement a background worker thread and I just can't remember how right at this moment :P
			// Setting this to false allows us to bypass the OS threading rules
			// Since we are dealing with file I/O this really NEEDS to go on a background thread
			CheckForIllegalCrossThreadCalls = false;
		}
		
		private void BtnBrowseClick (object sender, EventArgs e) 		{
			// Show folder browser dialog
			if (fbdProjectDir.ShowDialog() == DialogResult.OK) {
				txtProjectDir.Text = fbdProjectDir.SelectedPath;
			}
		}
		
		private void BtnClearLogClick(object sender, EventArgs e)
		{
			// Clear the log text box
			txtLog.Text = "";
		}
		
		private void BtnWatchClick (object sender, EventArgs e) 		{
			if (!bWatching) {
				String strFullPath = txtProjectDir.Text + txtSrcDir.Text;
					
				// Check our src directory is legitimate first
				if (!Directory.Exists(strFullPath)) {
					MessageBox.Show(strFullPath + " does not appear to exist or is not a valid directory.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
					return;
				}
				
				// Record some values
				strSrcDir = txtSrcDir.Text;
				strTargetDir = txtTargetDir.Text;
				
				// Clear our list from previous watches
				lstExtensions.Clear();
				
				// Will we monitor FTLs?
				if (chkFTL.Checked) {
					lstExtensions.Add("FTL");
				}
				
				// Will we monitor CSS?
				if (chkCSS.Checked) {
					lstExtensions.Add("CSS");
				}
				
				// Will we monitor image types?
				if (chkImages.Checked) {
					lstExtensions.Add("JPG");
					lstExtensions.Add("GIF");
					lstExtensions.Add("PNG");
				}
				
				// Set the path
				fswWatcher.Path = strFullPath;
				
				// Set events to monitor
				if (chkFileModify.Checked) {
					fswWatcher.NotifyFilter = fswWatcher.NotifyFilter | NotifyFilters.LastWrite;					
				}
				
				// Set to watch all files by default since this object doesn't support multipe filters
				fswWatcher.Filter = "*.*";
				
				// Set to watch sub dirs
				fswWatcher.IncludeSubdirectories = true;
				
				// Add event handlers
				fswWatcher.Changed += new FileSystemEventHandler(FileChanged);

				// Start watching
				bWatching = true;
				btnWatch.Text = "STOP";
				
				// Start event monitor
				fswWatcher.EnableRaisingEvents = true;
			} else {
				// Stop watching
				bWatching = false;
				btnWatch.Text = "WATCH";
				
				// Stop the event monitor
				fswWatcher.EnableRaisingEvents = false;
			}
		}
		
		private void FileChanged (object fswSource, FileSystemEventArgs e) {
			String strPath = e.FullPath.ToString();
			String strLastWriteTime = File.GetLastWriteTime(strPath).ToString();
			
			// If there is no path info stored yet or the value is not the same, then do our thing
			try {
				if (!fileWriteTime.ContainsKey(strPath) || fileWriteTime[strPath].ToString() != strLastWriteTime) {
					
					// The FSW object cannot have multiple file extensions (it's all or 1) so, we're going to check against our list
					// and if the user has not checked this one, we'll ignore it
					String strExt = strPath.Substring(strPath.Length - 3).ToUpper();
					if (lstExtensions.Contains(strExt)) {
					
						UpdateLog("File Changed: " + strPath + " (" + strLastWriteTime + ")");
						CopyFile(strPath);
						
						// Update our hastable with this file
						fileWriteTime[strPath] = strLastWriteTime;
					}
				}
			} catch(Exception ex) {
				UpdateLog("Uh oh, something went wrong (" + ex.Message.ToString() + ")");
			}
		}
		
		private void CopyFile (string strSrc) {
			// Do the actual copy
			try {
				// Do a simple replace of the src dir with the target dir
				String strTarget = strSrc.Replace(strSrcDir, strTargetDir);
				System.IO.File.Copy(strSrc, strTarget, true);
				
				UpdateLog("Copied to: " + strTarget);
			} catch (Exception ex) {
				UpdateLog("File copy failed (" + ex.Message.ToString() + ")");
			}
		}
		
		private void UpdateLog (string strLogEntry) {
			// Update the log text box (!)
			txtLog.Text += strLogEntry + System.Environment.NewLine;
		}
	}
}
